#include "SceneStateRepository.h"

const string SCENES_FILEPATH = "./scenes/";

SceneStateRepository::SceneStateRepository(void)
{
}

SceneStateRepository::~SceneStateRepository(void)
{
}

Scene* SceneStateRepository::load(string name) throw (PersistenceException)
{
	Scene* scene = new Scene(0,0,name);

	try
    {
         XMLPlatformUtils::Initialize();
    }
	catch (const XMLException& xmle)
    {
		throw PersistenceException(XMLString::transcode(xmle.getMessage()));
	}

	SAX2XMLReader* parser = XMLReaderFactory::createXMLReader();
	parser->setFeature(XMLUni::fgSAX2CoreValidation, true);

	SAX2SceneStateHandler* handler = new SAX2SceneStateHandler();
	handler->setScene(scene);
	parser->setContentHandler((ContentHandler*)handler);
	parser->setErrorHandler((ErrorHandler*)handler);

	try
	{
		string scenePathname(SCENES_FILEPATH);
		scenePathname.append(scene->getName()).append(".xml");
		XMLCh* xmlFile = XMLString::transcode(scenePathname.c_str());
		parser->parse(xmlFile);
    }
    catch (const XMLException& xmle)
	{
		throw PersistenceException(XMLString::transcode(xmle.getMessage()));
	}
	catch (const SAXParseException& saxpe)
	{
		throw PersistenceException(XMLString::transcode(saxpe.getMessage()));
	}
	catch (...)
	{
		throw PersistenceException("Unexpected exception");
	}

	delete parser;
	XMLPlatformUtils::Terminate();

	return scene;
}

void SceneStateRepository::load(string name, Scene* scene) throw (PersistenceException)
{
	try
    {
         XMLPlatformUtils::Initialize();
    }
	catch (const XMLException& xmle)
    {
		throw PersistenceException(XMLString::transcode(xmle.getMessage()));
	}

	SAX2XMLReader* parser = XMLReaderFactory::createXMLReader();
	parser->setFeature(XMLUni::fgSAX2CoreValidation, true);

	SAX2SceneStateHandler* handler = new SAX2SceneStateHandler();
	handler->setScene(scene);
	parser->setContentHandler((ContentHandler*)handler);
	parser->setErrorHandler((ErrorHandler*)handler);

	try
	{
		string scenePathname(SCENES_FILEPATH);
		scenePathname.append(scene->getName()).append(".xml");
		XMLCh* xmlFile = XMLString::transcode(scenePathname.c_str());
		parser->parse(xmlFile);
    }
    catch (const XMLException& xmle)
	{
		throw PersistenceException(XMLString::transcode(xmle.getMessage()));
	}
	catch (const SAXParseException& saxpe)
	{
		throw PersistenceException(XMLString::transcode(saxpe.getMessage()));
	}
	catch (...)
	{
		throw PersistenceException("Unexpected exception");
	}

	delete parser;
	XMLPlatformUtils::Terminate();
}

list<string> SceneStateRepository::loadKeys() throw (PersistenceException)
{
	list<string> sceneNames;
	File* file = new File(SCENES_FILEPATH);
	try
    {
         sceneNames = file->getFiles();
    }
	catch (const IOException& ioe)
    {
		throw PersistenceException(ioe.getMessage());
	}
	return sceneNames;
}

void SceneStateRepository::save(Scene* scene) throw (PersistenceException)
{
	try
    {
         XMLPlatformUtils::Initialize();
    }
	catch (const XMLException& xmle)
    {
		throw PersistenceException(XMLString::transcode(xmle.getMessage()));
	}

	XMLCh implName[100];
    XMLString::transcode("LS", implName, 99);
    DOMImplementation *xmlDOMImpl = DOMImplementationRegistry::getDOMImplementation(implName);
    DOMLSSerializer* xmlDOMSerializer = ((DOMImplementationLS*)xmlDOMImpl)->createLSSerializer();
	
	if (xmlDOMSerializer->getDomConfig()->canSetParameter(XMLUni::fgDOMWRTDiscardDefaultContent, true))
	{
		xmlDOMSerializer->getDomConfig()->setParameter(XMLUni::fgDOMWRTDiscardDefaultContent, true);
	}
	if (xmlDOMSerializer->getDomConfig()->canSetParameter(XMLUni::fgDOMWRTFormatPrettyPrint, true))
	{
		xmlDOMSerializer->getDomConfig()->setParameter(XMLUni::fgDOMWRTFormatPrettyPrint, true);
	}

	string scenePathname(SCENES_FILEPATH);
	scenePathname.append(scene->getName()).append(".xml");
	XMLFormatTarget *xmlFileTarget = new LocalFileFormatTarget(scenePathname.c_str());
    DOMLSOutput* xmlDOMOutput = ((DOMImplementationLS*)xmlDOMImpl)->createLSOutput();
    xmlDOMOutput->setByteStream(xmlFileTarget);
	
	xercesc::DOMDocument* xmlDocument = xmlDOMImpl->createDocument(0, XMLString::transcode("scene"), 0);
	DOMElement* rootElement = xmlDocument->getDocumentElement();
	rootElement->setAttribute(XMLString::transcode("name"), XMLString::transcode(scene->getName().c_str()));
	DOMElement* backgroundElement = xmlDocument->createElement(XMLString::transcode("background"));
	DOMElement* imageElement = xmlDocument->createElement(XMLString::transcode("image"));
	imageElement->setAttribute(XMLString::transcode("path"), XMLString::transcode(scene->getBackgroundPath().c_str()));
	backgroundElement->appendChild(imageElement);
    rootElement->appendChild(backgroundElement);
	DOMElement* shapesElement = xmlDocument->createElement(XMLString::transcode("objects"));
	
	DOMElement* shapeElement;
	DOMElement* geometryElement;
	SceneObject* shape;
	list<SceneObject*>::const_iterator it;
	for ( it = scene->getObjsLst()->begin(); it != scene->getObjsLst()->end(); it++)
	{
		shape = static_cast<SceneObject*>(*it);
		shapeElement = xmlDocument->createElement(XMLString::transcode("object"));
		shapeElement->setAttribute(XMLString::transcode("x_coordinate"), XMLString::transcode(toString(shape->getXCoordinate() - scene->getXCoordinate()).c_str()));
		shapeElement->setAttribute(XMLString::transcode("y_coordinate"), XMLString::transcode(toString(shape->getYCoordinate() - scene->getYCoordinate()).c_str()));
		//shapeElement->setAttribute(XMLString::transcode("name"), XMLString::transcode(toString(shape->getObjectType()).c_str()));
		shapeElement->setAttribute(XMLString::transcode("name"), XMLString::transcode((shape->getName()).c_str()));
		shapesElement->appendChild(shapeElement);
	}
	rootElement->appendChild(shapesElement);
	try
	{
		xmlDOMSerializer->write(xmlDocument, xmlDOMOutput);
    }
	catch (const XMLException& xmle)
	{
		throw PersistenceException(XMLString::transcode(xmle.getMessage()));
    }
    catch (const DOMException& dome)
	{
		throw PersistenceException(XMLString::transcode(dome.getMessage()));
    }
    catch (...)
	{
		throw PersistenceException("Unexpected exception");
    }

    xmlDOMOutput->release();
    xmlDOMSerializer->release();
	xmlDocument->release();
    delete xmlFileTarget;
		
	XMLPlatformUtils::Terminate();
}

void SceneStateRepository::remove(Scene* scene) throw (PersistenceException)
{
	string filename(SCENES_FILEPATH);
	filename.append(scene->getName()).append(".xml");
	File* file = new File(filename);
	try
	{
		file->remove();
	}
	catch (const IOException& ioe)
	{
		throw PersistenceException(ioe.getMessage());
	}
}

string SceneStateRepository::toString(int intValue)
{
	stringstream ss;
	ss << intValue;
	return ss.str();
}
